/*
 *  engine.cpp
 */

#include <iostream>
#include <string>
#include <vector>
#include "../../common/src/debug.h"
#include "../../common/src/lock.h"
#include "../../common/src/message.h"
#include "../../common/src/message_queue.h"
#include "../../common/src/session.h"
#include "../../common/src/util.h"
#include "app_listener.h"
#include "client_app.h"
#include "engine.h"

Engine::Engine(ClientApp* app) {
    this->app = app;
}

Engine::~Engine() {}

void Engine::run() {
    while (app->isRunning()) {
        processMessages();
        //render logic
    }
}

void Engine::processMessages() {
    while (!app->getMessageQueue().empty()) {
        Message* msg = app->getMessageQueue().pop();
        if (msg->getType() == Protocol::MSG_LIST_GAMES) {
            updateGameList(msg);
        } else if (msg->getType() == Protocol::MSG_CREATE_GAME_FAIL) {
            //update
        } else if (msg->getType() == Protocol::MSG_CREATE_GAME_OK) {
            processResponseGameCreateOk(msg);
        } else if (msg->getType() == Protocol::MSG_GAME_ABORT_OK) {
            processResponseGameAbortOk(msg);
        } else if (msg->getType() == Protocol::MSG_JOIN_GAME_FAIL) {
            //update
        } else if (msg->getType() == Protocol::MSG_JOIN_GAME_OK) {
            processResponseGameJoinOk(msg);
        } else if (msg->getType() == Protocol::MSG_PLAYER_JOINED) {
            processResponsePlayerJoined(msg);
        } else if (msg->getType() == Protocol::MSG_PLAYER_DISSEVERED) {
            processResponsePlayerDissevered(msg);
        } else if (msg->getType() == Protocol::MSG_START_GAME_FAIL) {
            //update
        } else if (msg->getType() == Protocol::MSG_START_GAME_OK) {
            processResponseGameStartOk(msg);
        }
        delete msg;
    }
}

void Engine::updateGameList(Message* msg) {
    //limit lock scope
    {
        Lock lock(app->getGames().getMutex());
        std::vector<GameInfo*>* v = app->getGames().getVector();
        for (int i = 0; i < v->size(); ++i) delete (*v)[i];
        v->clear();
        std::vector<std::string>* records = msg->getRecords();
        if (records != NULL && records->size() != 0) {
            std::vector<std::string>* units = NULL; 
            for (int i = 0; i < records->size(); ++i) {
                units = msg->getUnits((*records)[i]);
                if (units == NULL) continue;
                v->push_back(new GameInfo((*units)[0],
                                          (*units)[1],
                                          (*units)[2],
                                          (*units)[3],
                                          (*units)[4]));
                delete units;
            }
        }
        delete records;
    }
    //printGameList();
    Lock listeners_lock(app->getListeners().getMutex());
    std::list<AppListener*>* l = app->getListeners().getList();
    for (std::list<AppListener*>::iterator it = l->begin(); it != l->end(); it++) {
        (*it)->notifyGameInfoUpdate(app);
    }
}

void Engine::processResponseGameCreateOk(Message* msg) {
    Lock listeners_lock(app->getListeners().getMutex());
    std::list<AppListener*>* l = app->getListeners().getList();
    for (std::list<AppListener*>::iterator it = l->begin(); it != l->end(); it++) {
        (*it)->notifyGameCreateOk(app);
    }
}

void Engine::processResponseGameJoinOk(Message* msg) {
    Lock listeners_lock(app->getListeners().getMutex());
    std::list<AppListener*>* l = app->getListeners().getList();
    for (std::list<AppListener*>::iterator it = l->begin(); it != l->end(); it++) {
        (*it)->notifyGameJoinOk(app);
    }
}

void Engine::processResponsePlayerJoined(Message* msg) {
    Lock listeners_lock(app->getListeners().getMutex());
    std::list<AppListener*>* l = app->getListeners().getList();
    for (std::list<AppListener*>::iterator it = l->begin(); it != l->end(); it++) {
        (*it)->notifyPlayerJoined(app);
    }
}

void Engine::processResponsePlayerDissevered(Message* msg) {
    Lock listeners_lock(app->getListeners().getMutex());
    std::list<AppListener*>* l = app->getListeners().getList();
    for (std::list<AppListener*>::iterator it = l->begin(); it != l->end(); it++) {
        (*it)->notifyPlayerDissevered(app);
    }
}

void Engine::processResponseGameAbortOk(Message* msg) {
    Lock listeners_lock(app->getListeners().getMutex());
    std::list<AppListener*>* l = app->getListeners().getList();
    for (std::list<AppListener*>::iterator it = l->begin(); it != l->end(); it++) {
        (*it)->notifyGameAbortOk(app);
    }
}

void Engine::processResponseGameStartOk(Message* msg) {
    Lock listeners_lock(app->getListeners().getMutex());
    std::list<AppListener*>* l = app->getListeners().getList();
    for (std::list<AppListener*>::iterator it = l->begin(); it != l->end(); it++) {
        (*it)->notifyGameStartOk(app);
    }
}

/*
void Engine::printGameList() {
    // list locked from updateGameList, no lock needed
    std::vector<GameInfo*>* gamelist = app->getGames().getVector();
    for (int i = 0; i < gamelist->size(); ++i) {
        std::cout << "GameID=" + (*gamelist)[i]->getGameID()
                  << " GameName=" + (*gamelist)[i]->getGameName()
                  << " CampaignName=" + (*gamelist)[i]->getCampaignName()
                  << " Difficulty=" + (*gamelist)[i]->getCampaignDifficulty()
                  << " Players=" + (*gamelist)[i]->getPlayersSize()
                  << std::endl;
    }
}
*/

//{+}

